package com.asha.md360player4android.vr;

import android.app.Activity;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.asha.md360player4android.vr.display.CustomDisplayFactory;
import com.asha.md360player4android.vr.projection.CustomProjectionFactory;
import com.asha.vrlib.CalibrateInfo;
import com.asha.vrlib.MD360Renderer;
import com.asha.vrlib.MDVRLibrary;
import com.codecrecord.TextureMovieEncoder;
import com.google.android.apps.muzei.render.GLTextureView;

/**
 * Created by fuyao on 2016/12/21.
 */

public class VrManager {
    public static final int MODULE_INDEX_FISH_EYE = 0;
    public static final int MODULE_INDEX_PANORAMA = 1;
    public static final int MODULE_INDEX_PANORAMA_TWO = 2;
    public static final int MODULE_INDEX_TOP_BOTTOM_BLOCK = 3;
    public static final int MODULE_INDEX_FOUR_BLOCK = 4;
    public static final int MODULE_INDEX_PLANE = 5;
    public static final int MODULE_INDEX_FISH_EYE_CALIBRATE = 6;

    private static String TAG = "VrManager";
    private int mDisplayMode = MODULE_INDEX_TOP_BOTTOM_BLOCK;

    //    MDVRLibrary.PROJECTION_MODE_FISH_EYS_CALIBRATION
    private MDVRLibrary mVRLibrary;

    public VrManager(String tag) {
        TAG = tag + "_VrManager";
    }

    //for video
    public void createVRLibrary(Context context, View view,
                                MDVRLibrary.IOnSurfaceTextureReadyCallback callback,
                                MDVRLibrary.IGestureListener gestureListener, MDVRLibrary.OnSurfaceDestroyListener destroyListener,
                                MDVRLibrary.INotSupportCallback notSupportCallback) {
        MDVRLibrary.Builder builder = MDVRLibrary.with(context)
                .asVideo(callback)
                .listenGesture(gestureListener)
                .setOnSurfaceDestroyListener(destroyListener)
                .ifNotSupport(notSupportCallback)
                .displayFactory(new CustomDisplayFactory())
                .projectionFactory(new CustomProjectionFactory())
                .eyePickEnabled(false);
        coverDisplayMode(builder, mDisplayMode);
        if (view instanceof GLSurfaceView) {
            mVRLibrary = builder.build((GLSurfaceView) view);
        } else if (view instanceof GLTextureView) {
            mVRLibrary = builder.build((GLTextureView) view);
        } else {
            throw new IllegalArgumentException("view should be one of GLTextureView or GLSurfaceView");
        }
        Log.d(TAG, "createVRLibrary");
    }

    //for video
    public void createVRLibrary(final Activity activity, View view,
                                MDVRLibrary.IOnSurfaceReadyCallback callback,
                                MDVRLibrary.IGestureListener gestureListener, MDVRLibrary.OnSurfaceDestroyListener destroyListener) {
        MDVRLibrary.Builder builder = MDVRLibrary.with(activity)
                .asVideo(callback)
                .listenGesture(gestureListener)
                .setOnSurfaceDestroyListener(destroyListener)
                .ifNotSupport(new MDVRLibrary.INotSupportCallback() {
                    @Override
                    public void onNotSupport(int mode) {
                        String tip = mode == MDVRLibrary.INTERACTIVE_MODE_MOTION
                                ? "onNotSupport:MOTION" : "onNotSupport:" + String.valueOf(mode);
                        Toast.makeText(activity, tip, Toast.LENGTH_SHORT).show();
                    }
                })
                .displayFactory(new CustomDisplayFactory())
                .projectionFactory(new CustomProjectionFactory())
                .eyePickEnabled(false);
        coverDisplayMode(builder, mDisplayMode);
        if (view instanceof GLSurfaceView) {
            mVRLibrary = builder.build((GLSurfaceView) view);
        } else if (view instanceof GLTextureView) {
            mVRLibrary = builder.build((GLTextureView) view);
        } else {
            throw new IllegalArgumentException("view should be one of GLTextureView or GLSurfaceView");
        }
        Log.e(TAG, "createVRLibrary");
    }

    //for bitmap
    public void createVRLibrary(final Activity activity, View view,
                                MDVRLibrary.IBitmapProvider callback,
                                MDVRLibrary.IGestureListener gestureListener) {
        MDVRLibrary.Builder builder = MDVRLibrary.with(activity)
                .listenGesture(gestureListener)
                .ifNotSupport(new MDVRLibrary.INotSupportCallback() {
                    @Override
                    public void onNotSupport(int mode) {
                        String tip = mode == MDVRLibrary.INTERACTIVE_MODE_MOTION
                                ? "onNotSupport:MOTION" : "onNotSupport:" + String.valueOf(mode);
                        Toast.makeText(activity, tip, Toast.LENGTH_SHORT).show();
                    }
                })
                .asBitmap(callback)
                .displayFactory(new CustomDisplayFactory())
                .projectionFactory(new CustomProjectionFactory())
                .eyePickEnabled(false);
        coverDisplayMode(builder, mDisplayMode);
        if (view instanceof GLSurfaceView) {
            mVRLibrary = builder.build((GLSurfaceView) view);
        } else if (view instanceof GLTextureView) {
            mVRLibrary = builder.build((GLTextureView) view);
        } else {
            throw new IllegalArgumentException("view should be one of GLTextureView or GLSurfaceView");
        }
        Log.e(TAG, "createVRLibrary");
    }

    public void onPause(Context context) {
        if (null != mVRLibrary && !pause) {
            pause = true;
            mVRLibrary.onPause(context);
            Log.e(TAG, "onPause");
        }
    }

    private boolean pause = true;

    public void onResume(Context context) {
        if (null != mVRLibrary && pause) {
            pause = false;
            mVRLibrary.onResume(context);
            Log.e(TAG, "onResume");
        }
    }

    public void onDestroy() {
        if (null != mVRLibrary) {
            mVRLibrary.onDestroy();
            mVRLibrary = null;
            Log.e(TAG, "onDestroy");
        }
        mWidth = mHeight = -1;
    }

    public void notifyTextureChanged() {
        if (null != mVRLibrary) {
            mVRLibrary.notifyPlayerChanged();
            Log.e(TAG, "notifyTextureChanged");
        }
    }

    private int mWidth = -1;
    private int mHeight = -1;

    public void onTextureResize(int width, int height) {
        if (null != mVRLibrary) {
            if (mWidth == -1 || mHeight == -1 || width != mWidth || height != mHeight) {
                mWidth = width;
                mHeight = height;
                mVRLibrary.onTextureResize(width, height);
                calibrateInfo.setOriginWidth(width);
                calibrateInfo.setOriginHeight(height);
                Log.e(TAG, "onTextureResize width = " + width + " height = " + height);
            }
        }
    }

    public void notifyOrientationChanged(Context context) {
        if (null != mVRLibrary)
            mVRLibrary.onOrientationChanged(context);
    }

    public void notifyPlayerChanged() {
        if (null != mVRLibrary)
            mVRLibrary.notifyPlayerChanged();
    }

    public int getDisplayMode() {
        return mDisplayMode;
    }

    private MDVRLibrary.Builder coverDisplayMode(MDVRLibrary.Builder builder, int mode) {
        mDisplayMode = mode;
        builder.projectionMode(getProjectMode(mode));
        builder.interactiveMode(getInteractiveByMode(mode));
        builder.displayMode(getDisplayByMode(mode));
        builder.pinchEnabled(getPinchEnableByMode(mode));
        return builder;
    }

    public void onDisplayModeChange(int mode, Context context) {
        onDisplayModeChange(mode, context, true);
    }

    public void onDisplayModeChange(int mode, Context context, boolean save) {
        if (mDisplayMode == mode || null == mVRLibrary) {
            return;
        }
        mDisplayMode = mode;
        mVRLibrary.switchProjectionMode(context, getProjectMode(mode));
        mVRLibrary.switchInteractiveMode(context, getInteractiveByMode(mode));
        mVRLibrary.switchDisplayMode(context, getDisplayByMode(mode));
        mVRLibrary.setPinchEnabled(getPinchEnableByMode(mode));
    }

    private boolean getPinchEnableByMode(int mode) {
        boolean ret = false;
        switch (mode) {
            case MODULE_INDEX_FISH_EYE_CALIBRATE:
                ret = false;
                break;
            case MODULE_INDEX_FISH_EYE:
                ret = false;
                break;
            case MODULE_INDEX_PANORAMA:
                ret = true;
                break;
            case MODULE_INDEX_PANORAMA_TWO:
                ret = true;
                break;
            case MODULE_INDEX_TOP_BOTTOM_BLOCK:
                ret = true;
                break;
            case MODULE_INDEX_FOUR_BLOCK:
                ret = true;
                break;
            case MODULE_INDEX_PLANE:
                ret = false;
                break;
        }
        return ret;
    }

    private int getDisplayByMode(int mode) {
        int ret = -1;
        switch (mode) {
            case MODULE_INDEX_FISH_EYE_CALIBRATE:
//                ret = CustomDisplayFactory.CUSTOM_DISPLAY_MODE_NORMAL;
                ret = CustomDisplayFactory.CUSTOM_DISPLAY_MODE_CALIBRATE;
                break;
            case MODULE_INDEX_FISH_EYE:
                ret = CustomDisplayFactory.CUSTOM_DISPLAY_MODE_FISH_EYE;
                break;
            case MODULE_INDEX_PANORAMA:
                ret = CustomDisplayFactory.CUSTOM_DISPLAY_MODE_BLOCK_SINGLE;
                break;
            case MODULE_INDEX_PANORAMA_TWO:
                ret = CustomDisplayFactory.CUSTOM_DISPLAY_MODE_BLOCK_SINGLE_2;
                break;
            case MODULE_INDEX_TOP_BOTTOM_BLOCK:
                ret = CustomDisplayFactory.CUSTOM_DISPLAY_MODE_BLOCK_TOP_BOTTOM;
                break;
            case MODULE_INDEX_FOUR_BLOCK:
                ret = CustomDisplayFactory.CUSTOM_DISPLAY_MODE_BLOCK_FOUR_RECT;
                break;
            case MODULE_INDEX_PLANE:
                ret = CustomDisplayFactory.CUSTOM_DISPLAY_MODE_NORMAL;
                break;
        }
        return ret;
    }

    private int getInteractiveByMode(int mode) {
        int ret = -1;
        switch (mode) {
            case MODULE_INDEX_FISH_EYE_CALIBRATE:
                ret = MDVRLibrary.INTERACTIVE_MODE_TOUCH;
                break;
            case MODULE_INDEX_FISH_EYE:
                ret = MDVRLibrary.INTERACTIVE_MODE_TOUCH;
                break;
            case MODULE_INDEX_PANORAMA:
                ret = MDVRLibrary.INTERACTIVE_MODE_TOUCH;
                break;
            case MODULE_INDEX_PANORAMA_TWO:
                ret = MDVRLibrary.INTERACTIVE_MODE_TOUCH;
                break;
            case MODULE_INDEX_TOP_BOTTOM_BLOCK:
                ret = MDVRLibrary.INTERACTIVE_MODE_TOUCH;
                break;
            case MODULE_INDEX_FOUR_BLOCK:
                ret = MDVRLibrary.INTERACTIVE_MODE_TOUCH;
                break;
            case MODULE_INDEX_PLANE:
                ret = MDVRLibrary.INTERACTIVE_MODE_TOUCH;
                break;
        }
        return ret;
    }

    private int getProjectMode(int mode) {
        int ret = -1;
        switch (mode) {
            case MODULE_INDEX_FISH_EYE_CALIBRATE:
//                ret = CustomProjectionFactory.CUSTOM_PROJECT_CALIBRATE_CIRCLE;
                ret = CustomProjectionFactory.CUSTOM_PROJECT_CALIBRATE_DOME;
                break;
            case MODULE_INDEX_FISH_EYE:
                ret = CustomProjectionFactory.CUSTOM_PROJECT_DOME_PANORAMA_71_5;
                break;
            case MODULE_INDEX_PANORAMA:
                ret = CustomProjectionFactory.CUSTOM_PROJECT_DOME_PANORAMA_140;
                break;
            case MODULE_INDEX_PANORAMA_TWO:
                ret = CustomProjectionFactory.CUSTOM_PROJECT_DOME_PANORAMA_140;
                break;
            case MODULE_INDEX_TOP_BOTTOM_BLOCK:
                ret = CustomProjectionFactory.CUSTOM_PROJECT_DOME_PANORAMA_140;
                break;
            case MODULE_INDEX_FOUR_BLOCK:
                ret = CustomProjectionFactory.CUSTOM_PROJECT_DOME_PANORAMA_140;
                break;
            case MODULE_INDEX_PLANE:
                ret = MDVRLibrary.PROJECTION_MODE_PLANE_FIT;
                break;
        }
        return ret;
    }

    public void updateSensitivity(float sensitivity) {
        if (null != mVRLibrary) {
            mVRLibrary.updateSensitivity(sensitivity);
        }
    }

    private CalibrateInfo calibrateInfo = new CalibrateInfo(-1, -1);

    public int getRadiusProgress() {
        return (int) (calibrateInfo.getRadius() * 1000);
    }

    public int getCenterXProgress() {
        return (int) (calibrateInfo.getCenterX() * 500f + 500f);
    }

    public int getCenterYProgress() {
        return (int) (calibrateInfo.getCenterY() * 500f + 500f);
    }

    public int getOffsetXProgress() {
        return (int) (calibrateInfo.getOffsetX() * 500f + 500f);
    }

    public int getOffsetYProgress() {
        return (int) (calibrateInfo.getOffsetY() * 500f + 500f);
    }

    public float getRadius() {
        return calibrateInfo.getRadius();
    }

    public float getOffsetY() {
        return calibrateInfo.getOffsetY();
    }

    public float getOffsetX() {
        return calibrateInfo.getOffsetX();
    }

    public void setRadius(float radius) {
        calibrateInfo.setRadius(radius);
    }

    public void setOffsetX(float offset) {
        calibrateInfo.setOffsetX(offset);
    }

    public void setOffsetY(float offset) {
        calibrateInfo.setOffsetY(offset);
    }

    public float setRadiusProgress(int progress) {
        calibrateInfo.setRadius(progress * 0.001f * 1f);
        return calibrateInfo.getRadius();
    }

    public float setCenterXProgress(int progress) {
        calibrateInfo.setCenterX((progress - 500) * 2f * 0.001f * 1f);
        return calibrateInfo.getCenterX();
    }

    public float setCenterYProgress(int progress) {
        calibrateInfo.setCenterY((progress - 500) * 2f * 0.001f * 1f);
        return (progress - 500) * 2f * 0.001f * 1f;
    }

    public float setOffsetXProgress(int progress) {
        calibrateInfo.setOffsetX((progress - 500) * 2f * 0.001f * 1f);
        return calibrateInfo.getCenterX();
    }

    public float setOffsetYProgress(int progress) {
        calibrateInfo.setOffsetY((progress - 500) * 2f * 0.001f * 1f);
        return calibrateInfo.getOffsetY();
    }

    public void notifyCalibrateChange(Context context) {
        if (null != mVRLibrary) {
            mVRLibrary.notifyCalibrateChange(calibrateInfo, context);
        }
    }

    public void saveCalibrate(Context context) {
        float[] calibrates = new float[5];
        calibrates[0] = calibrateInfo.getOriginWidth();
        calibrates[1] = calibrateInfo.getOriginHeight();
        calibrates[2] = calibrateInfo.getRadius();
        calibrates[3] = calibrateInfo.getOffsetX();
        calibrates[4] = calibrateInfo.getOffsetY();
        SharePreferenceManager.setCalibrate(context, calibrates);
    }

    public boolean doCapture(MD360Renderer.OnCaptureOverListener onCaptureOverListener) {
        if (null == mVRLibrary) return false;
        return mVRLibrary.doCapture(onCaptureOverListener);
    }

    public int initRecord(String path, boolean voice) {
        if (null != mVRLibrary) {
            return mVRLibrary.initRecord(path, voice);
        }
        return -100;
    }

    public int startRecord(TextureMovieEncoder.OnVideoDone onVideoDone){
        if (null != mVRLibrary) {
            return mVRLibrary.startRecord(onVideoDone);
        }
        return -100;
    }

    public void stopRecord(){
        if (null != mVRLibrary) {
            mVRLibrary.stopRecord();
        }
    }

}
